<?php

 class __driver_acsgp {
 	
 	protected $noAuthGRP = 1;
 	static protected $acsgp_info = array();
 	
 	
 	/**
 	 * Вернет ID группы в которой участвует пользователь.
 	 * Если пользователь находится в нескольких группах, вернет массив
 	 * 
 	 * @return mixed
 	 */
    public function getMyGrp() {
    	if(!isset($_SESSION['user']['acsgp'])) return $this->noAuthGRP;
    	elseif(is_numeric($_SESSION['user']['acsgp']))
    		return $_SESSION['user']['acsgp'];
    	else {
    		return explode('|', $_SESSION['user']['acsgp']);
    	}
    }
 	
    
    /**
     * Ответ на вопрос "Имею ли я доступ"
     * 
     * @param mixed $access - или число указывающее уровень доступа или роль 
     * @param mixed $module - если false значит проверить на доступ, если указан, значит нужно проверить на роль
     * @param mixed $mygp   - принудительное указание группы, только число. Если указано getGRPinfo не выполняется
     * @return bool
     */
 	public function doIHaveAccess($access, $module = false, $mygp = false) {
 		// Если принудительно не указанна группа получим данные о всех группах текущего пользователя
 		if($mygp === false) {
 			$mygp = $this->getMyGrp(); // Получим список группе к которой пренадлежит пользователь. Массив или число
 			$this->getGRPinfo($mygp);  // Удостоверимся в том, что информация на эту группу существует
 		}
 		
 		// Если необходимо проверить наличие доступа к праву у модуля
 		if($module !== false) {
 		
 			// Если указанная группа не массив - проверим наличие доступа
 			if(!is_array($mygp)) {
 				
	 			// Если такое правило определено в базе данных
	 			if(isset(self::$acsgp_info[$module][$mygp][$access])) {
	 				return (self::$acsgp_info[$module][$mygp][$access]==1?true:false); // ... вернем именно это значение
	 				
	 			// Если нет, посмотрим, есть ли оно в наборе правил конфигурации модуля и вернем значение по умолчанию
 				} else {
	 				// Проверим на существование конфигурации. Если её нет, значит проверить возможность доступа к правилу невозможно, что означает крах всего
	 				if(class_exists("__module_{$module}_config", true)) {
	 					$acs = &ginst("{$module}_config")->getAccessMap(); // Поскольку объект класса уже создан, данные о доступе сохранять в общую карту доступа нет смысла, будем теперь каждый раз смотреть сюда
	 					
	 					// Проверим условие которое просят, если условие не найдено, вызовем критическую ошибку, т.к. лучше вызвать крах, чем дать доступ к тому, чему нельзя
	 					if(isset($acs[$access][0])) {
	 						
	 						// Разрешать доступ нужно только тогда, когда доступ разрешен, а не НЕЗАПРЕЩЕН
	 						return ($acs[$access][0]==1?true:false);
	 						
	 					} else trigger_error("drv(ACSGP): Rule '{$access}' for module '{$module}' not found", E_USER_ERROR);
	 					
	 				} else trigger_error("drv(ACSGP): Config for module '{$module}' not found!", E_USER_ERROR);
	 			}

	 		// Если $mygp - это массив, рекурсивно выполним проверку по всем позициям массива
 			} else {
 				foreach($mygp as $gp) {
 					if(isset(self::$acsgp_info[$module][$gp][$access])) return (self::$acsgp_info[$module][$gp][$access]==1?true:false);
 					
 					if(!isset($GP))
 						$GP = gp;
 				}
 				
 				// Если относительно права ничего не ясно, вернем умолчание, используя первую группу, рекурсивно вызвал doIHaveAccess с третим параметвом в котором первая группа пользователя
 				return $this->doIHaveAccess($access, $module, $GP);
 			}
 			
 			
 		} else {
 			$MyAccesses = $this->mergeAccessesByGroups($mygp);
 			return $MyAccesses[$access];
 			
 		}
 	}
 	
 	/*
 	public function iAmAdmin() {
                return $this->doIHaveAccess(2);
 	}
 	*/
 	
 	/**
 	 * Вернет массив значений доступа для группы или массива групп
 	 * 
 	 * @param int $acsgp
 	 * @return array($access=>true)
 	 */
 	public function getAccesses($acsgp = false) {
 		if($acsgp === false) $acsgp = $this->getMyGrp();
 		
 		$this->getGRPinfo($acsgp);
 		
 		if(!is_array($acsgp)) {
 			return self::$acsgp_info[$acsgp];
 		} else
 			return $this->mergeAccessesByGroups($acsgp);
 	}
 	
 	/**
 	 * Превращает список групп в хеш возможных доступов.
 	 * 
 	 * @param array $groups
 	 * @return array
 	 */
 	public function mergeAccessesByGroups($groups) {
 		if(!is_array($groups) && is_array(self::$acsgp_info[$groups])) return self::$acsgp_info[$groups];
 		
 		$returnACSS = array();
 		foreach($groups as $group) {
 			foreach(self::$acsgp_info[$group] as $acs=>$value) {
 				$returnACSS[$acs] = $value;
 			}
 		}
 		
 		return $returnACSS;
 	}
 	
  	/**
 	 * Вернет массив групп которые получит из базы
 	 * 
 	 * @return array
 	 */
 	public function getGroups($id_in_key = false) {
 		$res=drv(DB)->query("SELECT * FROM `acsgp` ORDER BY `acsgp` ASC");
	    while($row=$res->fetchRow(DB_FETCHMODE_ASSOC)) {
	    	if($id_in_key == false) $ret[] = $row;
	    	else $ret[$row['acsgp']] = $row;
	    }
 		
 		return $ret;
 	}
 	
 	/**
 	 * Вернет информацию о группе по её ID
 	 * 
 	 * @param $access
 	 * @return array
 	 */
 	public function getGroupById($access) {
 		$res=drv(DB)->query("SELECT * FROM `acsgp` WHERE `acsgp` = ? LIMIT 1", array((int)$access));
	    $row=$res->fetchRow(DB_FETCHMODE_ASSOC);
	    	
 		return $row;
 	}
 	
 	/**
 	 * Вернет массив с названием всех уровней
 	 * 
 	 * @return array
 	 */
 	public function getAccessesNames($access_in_index = true, $orderBy='access') {
 		if($orderBy != 'access' && $orderBy != 'name') trigger_error("drv(ACSGP): Wrong order: {$orderBy}", E_USER_ERROR);
 		
 		$res=drv(DB)->query("SELECT * FROM `access_names` ORDER BY `{$orderBy}` ASC");
 		$i=0;
	    while($row=$res->fetchRow(DB_FETCHMODE_ASSOC)) {
	    	
	    	if($access_in_index == true) {
	    		$i++;
	    		$row['i'] = $i;
	    		$ret[$row['access']] = $row;
	    	}
	    	else $ret[] = $row;
	    }
 		
 		return $ret;
 	}
 	
 	
 	/**
 	 * Выгрузит из БД информацию по группе, если ранее это действие не производилось
 	 * 
 	 * @param int $acsgp
 	 * @return void
 	 */
 	private function getGRPinfo($acsgp) {
 		// Если необходима информация по одной группе, и $acsgp не массив
 		if(!is_array($acsgp)) {
	 		
 			if(!is_array(self::$acsgp_info[$acsgp])) {
		 		$res=drv(DB)->query("SELECT * FROM `acsgp_access` WHERE `acsgp_id` = ?", array((int)$acsgp));
			    while($row=$res->fetchRow(DB_FETCHMODE_ASSOC)) {
			    	$this->getGRPinfo_save_row($row);
			    }
	 		}
	 		
	 	// Для получения информации по нескольким группам в один запрос
 		} else {
 			$where = $array = array();
 			
 			foreach($acsgp as $grp) {
 				
 				if(is_numeric($grp) && !is_array(self::$acsgp_info[$grp])) {
 					$where[] = "`acsgp_id` = ?";
 					$array[] = $grp;
 				}
 			}
 			if(count($where) > 0) {
	 			$res=drv(DB)->query("SELECT * FROM `acsgp_access` WHERE ".implode(' OR ', $where), $array);
			    while($row=$res->fetchRow(DB_FETCHMODE_ASSOC)) {
			    	$this->getGRPinfo_save_row($row);
			    }
 			}
 		
 		}
 	}
 	
 	// Вспомогательная функция для getGRPinfo, которая сохраняет в хранилище информацию о доступе пользователя, т.к. этот функционал необходимо использовать в нескольких местах метода
 	private function getGRPinfo_save_row($row) {
 		if(!empty($row['module']) && !empty($row['access_name'])) {
	    	self::$acsgp_info[$row['module']][$row['acsgp_id']][$row['access_name']] = $row['access'];	
	    } else {
	    	self::$acsgp_info[$row['acsgp_id']][$row['access']] = true;
	    }
 	}
 	
    // Hold an instance of the class
    private static $instance;
    
    // A private constructor; prevents direct creation of object
    private function __construct() 
    {
        
    }

    // The singleton method
    public static function si() 
    {
        if (!isset(self::$instance)) {
            $c = __CLASS__;
            self::$instance = new $c;
        }

        return self::$instance;
    }

    // Prevent users to clone the instance
    public function __clone()
    {
        trigger_error('Clone is not allowed.', E_USER_ERROR);
    }
 
 }

?>
